unit UColumns;

interface

uses SysUtils, IniFiles, Classes, DBGrids, Generics.Collections;

const
  CColumnWidths = '%s.columns_width';

type
  TIntegerList = TList<integer>;
  TColumns = class(TObject)
  private
    FNames: THashedStringList;
    FWidths: TIntegerList;
    FTableName: string;
    FSection: string;
    FCount: integer;
    FCaptions: THashedStringList;
    FOwnsObject: boolean;
  public
    procedure Clear;
    procedure Assign(Columns: TDBGridColumns);
    procedure AssignTo(Columns: TDBGridColumns);
    function LoadFromFile(f: TIniFile): TColumns;
    function SaveToFile(f: TIniFile): TColumns;
    constructor Create(Table: string; ACaptions: THashedStringList = nil;
      const AOwnsObject: boolean = False);
    destructor Destroy; override;
  end;

implementation

{ TColumns }

procedure TColumns.Assign(Columns: TDBGridColumns);
var
  C: TColumn;
  i: integer;
begin
  if not Assigned(Columns) then
    Exit;
  Clear;
  FCount := Columns.Count;
  for i := 0 to FCount - 1 do begin
    C := Columns[i];
    C.DisplayName;
    C.Index;
    FWidths.Add(C.Width);
    FNames.Add(C.FieldName);
  end;
end;

procedure TColumns.AssignTo(Columns: TDBGridColumns);      
var
  C: TColumn;
  i: integer;
begin          
  if not Assigned(Columns) then
    Exit;
  Columns.Clear;
  for i := 0 to FCount - 1 do begin
    C := TColumn.Create(Columns);
    C.FieldName := FNames[i];
    if FCaptions.IndexOfName(FNames[i]) < 0 then
      C.Title.Caption := FNames[i]
    else
      C.Title.Caption := FCaptions.Values[FNames[i]];
    C.Width := FWidths[i];
  end;
end;

procedure TColumns.Clear;
begin   
  FNames.Clear;
  FWidths.Clear;
end;

constructor TColumns.Create(Table: string; ACaptions: THashedStringList = nil;
  const AOwnsObject: boolean = False);
begin
  FTableName := Table;
  FNames := THashedStringList.Create;
  FWidths := TIntegerList.Create;
  FSection := Format(CColumnWidths, [FTableName]);
  if not Assigned(ACaptions) then
    FCaptions := THashedStringList.Create
  else
    FCaptions := ACaptions;
  FOwnsObject := AOwnsObject and (FCaptions = ACaptions);
end;

destructor TColumns.Destroy;
begin
  if FOwnsObject then
    FreeAndNil(FCaptions);
  inherited;
end;

function TColumns.LoadFromFile(f: TIniFile): TColumns;
const
  DefWidth = 50;
var
  s: string;
begin
  Result := Self;
  Clear;
  f.ReadSection(FSection, FNames);
  Fcount := FNames.Count;
  for s in FNames do
    FWidths.Add(f.ReadInteger(FSection, s, DefWidth));
end;

function TColumns.SaveToFile(f: TIniFile): TColumns;
var
  i: integer;
begin
  Result := Self;
  f.EraseSection(FSection);
  for i := 0 to FCount - 1 do
    f.WriteInteger(FSection, FNames[i], FWidths[i]);
end;

end.
